本篇是實作常用的 AWS CloudWatch 與 EventBridge 服務之 Terraform 模組,並且會使用到 YAML 資料結構來定義模組的內容,完整的專案程式碼分享在我的 Github 上。
./configs/cloudwatch/loggroups.yaml
與 模組 my_cloudfront
的放置位置 modules/my_cloudwatch
:├── configs
│ ├── cloudfront
│ │ └── distributions.yaml
│ ├── cloudwatch
│ │ └── loggroups.yaml
│ ├── iam
│ │ ├── assume_role_policies
│ │ ├── policies
│ │ ├── role_policies
│ │ ├── user_policies
│ │ └── iam.yaml
│ ├── s3
│ │ ├── policies
│ │ └── s3.yaml
│ ├── subnet
│ │ └── my-subnets.yaml
│ └── vpc
│ └── my-vpcs.yaml
├── example.tfvars
├── locals.tf
├── main.tf
├── modules
│ ├── my_cloudfront
│ ├── my_cloudwatch
│ │ ├── cloudwatch.tf
│ │ ├── outputs.tf
│ │ ├── provider.tf
│ │ └── variables.tf
│ ├── my_eips
│ ├── my_eventbridge
│ │ ├── outputs.tf
│ │ ├── provider.tf
│ │ ├── rule.tf
│ │ ├── target.tf
│ │ └── variables.tf
│ ├── my_iam
│ ├── my_igw
│ ├── my_instances
│ ├── my_nacls
│ ├── my_route_tables
│ ├── my_s3
│ ├── my_subnets
│ └── my_vpc
└── variables.tf
./configs/eventbridge/events.yaml
、模組 my_eventbridge
的放置位置 modules/my_eventbridge
和放置 event pattern JSON file 的目錄 ./configs/eventbridge/patterns
:├── configs
├── cloudwatch
│ └── cloudwatch.yaml
├── eventbridge
│ ├── events.yaml
│ └── patterns
│ ├── iam
│ │ ├── assume_role_policies
│ │ ├── policies
│ │ ├── role_policies
│ │ ├── user_policies
│ │ └── iam.yaml
│ ├── s3
│ │ ├── policies
│ │ └── s3.yaml
│ ├── subnet
│ │ └── my-subnets.yaml
│ └── vpc
│ └── my-vpcs.yaml
├── example.tfvars
├── locals.tf
├── main.tf
├── modules
│ ├── my_cloudwatch
│ │ ├── cloudwatch.tf
│ │ ├── outputs.tf
│ │ ├── provider.tf
│ │ └── variables.tf
│ ├── my_eips
│ ├── my_eventbridge
│ │ ├── outputs.tf
│ │ ├── provider.tf
│ │ ├── rule.tf
│ │ ├── target.tf
│ │ └── variables.tf
│ ├── my_iam
│ ├── my_igw
│ ├── my_instances
│ ├── my_nacls
│ ├── my_route_tables
│ ├── my_s3
│ ├── my_subnets
│ └── my_vpc
└── variables.tf
./configs/cloudwatch/cloudwatch.yaml
內容來定義 CloudWatch 需要用建立的資源:loggroups:
- loggroup_name: "<LOGGROUP_NAME>"
retention_in_days: <RETENTION_IN_DAYS>
./configs/eventbridge/eventbridge.yaml
內容來定義 EventBridge 需要用建立的資源:rules:
- name: "<RULE_NAME>"
description: "<RULE_DESCRIPTION>"
event_bus_name: "<EVENT_BUS_NAME>"
event_pattern_file: "<EVENT_PATTERN_FILE_PATH>"
enabled: <true or false>
targets:
- arn: "<TARGET_ARN>"
rule_name: "<RULE_NAME>"
target_id: "<TARGET_ID>"
my_cloudwatch
模組:./modules/my_cloudwatch/outputs.tf
:output "loggroup" {
value = aws_cloudwatch_log_group.log_group
}
./modules/my_cloudwatch/provider.tf
:provider "aws" {
region = var.aws_region
profile = var.aws_profile
}
./modules/my_cloudwatch/variables.tf
:variable "aws_region" {
description = "AWS region"
default = "ap-northeast-1"
}
variable "aws_profile" {
description = "AWS profile"
default = ""
}
variable "project_name" {
type = string
description = "Project name"
default = ""
}
variable "department_name" {
type = string
description = "Department name"
default = "SRE"
}
variable "cloudwatch_path" {
description = "Cloudwatch path"
default = ""
}
./modules/my_cloudwatch/cloudwatch.tf
:locals {
cloudwatch_loggroups = yamldecode(file("${var.cloudwatch_path}"))["loggroups"]
}
resource "aws_cloudwatch_log_group" "log_group" {
for_each = { for r in local.cloudwatch_loggroups : r.loggroup_name => r }
name = each.value.loggroup_name
retention_in_days = each.value.retention_in_days
tags = {
Name = each.value.loggroup_name
Department = var.department_name
Project = var.project_name
}
tags_all = {
Name = each.value.loggroup_name
Department = var.department_name
Project = var.project_name
}
}
my_eventbridge
模組:./modules/my_eventbridge/outputs.tf
:output "rule" {
value = aws_cloudwatch_event_rule.rule
}
output "target" {
value = aws_cloudwatch_event_target.target
}
./modules/my_eventbridge/provider.tf
:provider "aws" {
region = var.aws_region
profile = var.aws_profile
}
./modules/my_eventbridge/variables.tf
:variable "aws_region" {
description = "AWS region"
default = "ap-northeast-1"
}
variable "aws_profile" {
description = "AWS profile"
default = ""
}
variable "project_name" {
type = string
description = "Project name"
default = ""
}
variable "department_name" {
type = string
description = "Department name"
default = "SRE"
}
./modules/my_eventbridge/rule.tf
:locals {
rules = yamldecode(file("${var.eventbridge_path}"))["rules"]
}
resource "aws_cloudwatch_event_rule" "rule" {
for_each = { for r in local.rules : r.name => r }
name = each.value.name
description = each.value.description
event_bus_name = each.value.event_bus_name
event_pattern = file("${each.value.event_pattern_file}")
is_enabled = each.value.enabled
}
./modules/my_eventbridge/target.tf
:locals {
targets = yamldecode(file("${var.eventbridge_path}"))["targets"]
}
resource "aws_cloudwatch_event_target" "target" {
for_each = { for r in local.targets : r.target_id => r }
arn = each.value.arn
rule = each.value.rule_name
target_id = each.value.target_id
depends_on = [
aws_cloudwatch_event_rule.rule
]
}
example.tfvars
:aws_region="ap-northeast-1"
aws_profile="<YOUR_PROFILE>"
project_name="example"
department_name="SRE"
main.tf
:terraform {
required_providers {
aws = {
version = "5.15.0"
}
}
backend "s3" {
bucket = "<YOUR_S3_BUCKET_NAME>"
dynamodb_table = "<YOUR_DYNAMODB_TABLE_NAME>"
key = "terraform.tfstate"
region = "ap-northeast-1"
shared_credentials_file = "~/.aws/config"
profile = "<YOUR_PROFILE>"
}
}
其他模組省略...
# cloudwatch loggroup
module "cloudwatch" {
aws_profile = var.aws_profile
aws_region = var.aws_region
environment = var.environment
department_name = var.department_name
project_name = var.project_name
cloudwatch_path = "./configs/cloudwatch/loggroups.yaml"
source = "./modules/my_cloudwatch"
}
# cloudwatch eventbridge
module "EventBridge" {
aws_profile = var.aws_profile
aws_region = var.aws_region
eventbridge_path = "./configs/eventbridge/events.yaml"
source = "./modules/my_eventbridge"
}
loggroups:
- loggroup_name: "/example/my_loggroup"
retention_in_days: 7
terraform init && terraform plan --out .plan -var-file=example.tfvars
來確認一下結果:
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
...
# module.cloudwatch.aws_cloudwatch_log_group.log_group["/example/my_loggroup"] will be created
+ resource "aws_cloudwatch_log_group" "log_group" {
+ arn = (known after apply)
+ id = (known after apply)
+ name = "/example/my_loggroup"
+ name_prefix = (known after apply)
+ retention_in_days = 7
+ skip_destroy = false
+ tags = {
+ "Department" = "SRE"
+ "Name" = "/example/my_loggroup"
+ "Project" = "example"
}
+ tags_all = {
+ "Department" = "SRE"
+ "Name" = "/example/my_loggroup"
+ "Project" = "example"
}
}
...
Plan: 48 to add, 0 to change, 0 to destroy.
─────────────────────────────────────────────────────────────────────────────
Saved the plan to: .plan
To perform exactly these actions, run the following command to apply:
terraform apply ".plan"
Releasing state lock. This may take a few moments...
下一篇文章將會展示實作 AWS Kinesis Firehose 與 Stream 之 Terraform 模組。